﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace GameCamera
{
  public class Camera
  {
    private float yaw, pitch, roll, speed;
    private Vector3 position, target;
    public Matrix viewMatrix, projectionMatrix, cameraRotation;
    private bool WASDCamera;
    public Viewport viewport;
    private float aspectRatio;
    private BoundingFrustum cameraFrustum;

    public BoundingFrustum CameraFrustum
    {
      get { return cameraFrustum; }
    }

    public Vector3 Position
    {
      get { return position; }
    }

    public Camera(bool WASDCamera, Vector3 position, Viewport viewport)
    {
      this.WASDCamera = WASDCamera;
      this.viewport = viewport;
      this.cameraFrustum = new BoundingFrustum(Matrix.Identity);
      yaw = pitch = roll = 0.0f;
      speed = 0.3f;
      this.position = position;
      target = new Vector3();
      viewMatrix = Matrix.Identity;
      aspectRatio = (float)viewport.Width / (float)viewport.Height;
      projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(60.0f), aspectRatio , 0.5f, 500.0f);
      cameraRotation = Matrix.Identity;
    }

    private void HandleInput()
    {
      KeyboardState keyboardState = Keyboard.GetState();

      if (!WASDCamera)
      {
        if (keyboardState.IsKeyDown(Keys.I))
        {
          MoveCamera(cameraRotation.Forward);
        }
        if (keyboardState.IsKeyDown(Keys.K))
        {
          MoveCamera(-cameraRotation.Forward);
        }
        if (keyboardState.IsKeyDown(Keys.J))
        {
          MoveCamera(-cameraRotation.Right);
        }
        if (keyboardState.IsKeyDown(Keys.L))
        {
          MoveCamera(cameraRotation.Right);
        }
        if (keyboardState.IsKeyDown(Keys.O))
        {
          MoveCamera(cameraRotation.Up);
        }
        if (keyboardState.IsKeyDown(Keys.U))
        {
          MoveCamera(-cameraRotation.Up);
        }
        if (keyboardState.IsKeyDown(Keys.N))
        {
          yaw -= .02f;
        }
        if (keyboardState.IsKeyDown(Keys.M))
        {
          yaw += .02f;
        }
      }
      else
      {

        if (keyboardState.IsKeyDown(Keys.W))
        {
          MoveCamera(cameraRotation.Forward);
        }
        if (keyboardState.IsKeyDown(Keys.S))
        {
          MoveCamera(-cameraRotation.Forward);
        }
        if (keyboardState.IsKeyDown(Keys.A))
        {
          MoveCamera(-cameraRotation.Right);
        }
        if (keyboardState.IsKeyDown(Keys.D))
        {
          MoveCamera(cameraRotation.Right);
        }
        if (keyboardState.IsKeyDown(Keys.E))
        {
          MoveCamera(cameraRotation.Up);
        }
        if (keyboardState.IsKeyDown(Keys.Q))
        {
          MoveCamera(-cameraRotation.Up);
        }
        if (keyboardState.IsKeyDown(Keys.Z))
        {
          yaw += .02f;
        }
        if (keyboardState.IsKeyDown(Keys.X))
        {
          yaw -= .02f;
        }
      }
    }

    private void MoveCamera(Vector3 addedVector)
    {
      position += speed * addedVector;
    }

    public void Update()
    {
      HandleInput();
      UpdateViewMatrix();
    }

    public void UpdateViewMatrix()
    {
      cameraRotation.Forward.Normalize();
      cameraRotation.Up.Normalize();
      cameraRotation.Right.Normalize();

      cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Right, pitch);
      cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Up, yaw);
      cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Forward, roll);

      yaw = 0.0f;
      pitch = 0.0f;
      roll = 0.0f;

      target = position + cameraRotation.Forward;

      viewMatrix = Matrix.CreateLookAt(position, target, cameraRotation.Up);
      viewMatrix = Matrix.CreateLookAt(position, target, Vector3.Up);

      cameraFrustum.Matrix = viewMatrix * projectionMatrix; 
    }
  }
}
